interface InputTemplate {
    pitch: number;
    rate: number;
}

function PFromC(c: number) {
    let dCurP = 0;
    let dPreSuccessP = 0;
    let dPE = 0;
    let nMaxFail = Math.ceil(1 / c);
    for (let i = 1; i <= nMaxFail; ++i) {
        dCurP = Math.min(1, i * c) * (1 - dPreSuccessP);
        dPreSuccessP += dCurP;
        dPE += i * dCurP;
    }
    return 1 / dPE;
}
function CFromP(p: number) {
    let dUp = p;
    let dLow = 0;
    let dMid = p;
    let dPLast = 1;
    while (true) {
        dMid = (dUp + dLow) / 2;
        let dPTested = PFromC(dMid);
        if (Math.abs(dPTested - dPLast) <= 0.00005) break;
        if (dPTested > p) dUp = dMid;
        else dLow = dMid;
        dPLast = dPTested;
    }
    return dMid;
}

// 暴击率算法
// 借鉴于 https://www.bilibili.com/read/cv7466514/
export class PRDController {
    p: number;
    c: number;
    recordTime: number = 0;

    /** 暴击率算法，每次不暴击会累计暴击率
     * @param rate 平均暴击率
     */
    constructor({ rate }: InputTemplate) {
        this.p = rate;
        this.c = CFromP(rate);
    }
    /**
     * 生成这一次的暴击率
     * @param isCrit 上一次是否暴击
     * @returns number 暴击率
     */
    update(isCrit: boolean) {
        if (isCrit) this.recordTime = 0;
        this.recordTime++;
        const thisRate = this.c * this.recordTime;
        if (thisRate > 1) {
            this.recordTime = 0;
            return 1;
        } else {
            return thisRate;
        }
    }
}
